#pragma once
#define OIS_DYNAMIC_LIB

#include "stdafx.h"
#include "ControlStatus.h"
#include "ControlContext.h"
#include "EntityControl.h"

#include "ContactReport.h"

#include "PlayerControlElement.h"
#include "PlayerController.h"
#include "PlayerControlLogic.h"

#include "Target.h"
#include "TargetController.h"
#include "TargetControlLogic.h"
#include "Launcher.h"

#include "Trigger.h"
#include "DamageAction.h"
#include "PositionReq.h"
#include "RoundCamera.h"
#include "KilledReq.h"
#include "GameOverAction.h"
#include "ExplodeAction.h"
#include "CustomScriptAction.h"
#include "include/NegateReq.h"
#include "include/KillAction.h"

#include "PSysFromScript.h"

#include "LuaFunctionAdapter.h"
#include "CurveGenerator.h"
#include "BodyRailControlLogic.h"
#include "MapConfiguration.h"

#include "AIControlLogic.h"
#include "AIGoal.h"
#include "OnRailMoveAction.h"
#include "FreeMoveAction.h"
#include "FreeRayReq.h"
#include "EntityParameter.h"
#include "VectorEntityParameter.h"
//#include "HUD.h"
#include "OgreEntityBody.h"
#include "PhysicsEntityBody.h"
#include "ParticleEntityBody.h"
#include "NodeEntityBody.h"

#include "StackAllocatorManager.h"
#include "StackAllocator.h"
#include "IStackAllocator.h"

#include "include/PlayerProjectileControlLogic.h"

#include "UltimatePhysicsScene.h"
#include "UltimatePhysicsSubsystem.h"
#include "UltimateSoundSubsystem.h"
#include "UltimateInputSubsystem.h"
#include "include/UltimatePhysicsSubsystemMock.h"
#include "include/UltimateSoundMock.h"
#include "include/CustomScriptFileReader.h"
#include "include/GameOverHandler.h"

#include "include/NetworkControlLogic.h"
#include "UltimateNetworkSubsystem.h"

// Something for collision reaction
//extern ContactAddedCallback gContactAddedCallback;

class _OgreMoveExport Game : public Ogre::FrameListener
{


	bool rCameraUsed;
	RoundCamera *rCamera;


	//Move::IMoveManager* move;

	lua_State *LuaState;


	Ogre::TexturePtr camImage;
	//MyGUI::StaticImagePtr image;

	//CEGUI::OgreRenderer* mRenderer;

	//OgreBulletDynamics::DynamicsWorld *mWorld;	// OgreBullet World
	//OgreBulletCollisions::DebugDrawer *debugDrawer;
	//int mNumEntitiesInstanced;

	//std::deque<OgreBulletDynamics::RigidBody *>         mBodies;
	//std::deque<OgreBulletCollisions::CollisionShape *>  mShapes;
	//Ogre::Vector3 gravityVector;
	//Ogre::AxisAlignedBox bounds;


	std::deque<Ogre::ParticleSystem*> pSystems;
	short pSystemZeroCount;

	// PhysX specific parts
	/*NxScene* mNxScene;
	NxSceneDesc mNxSceneDesc;*/
	UltimatePhysicsScene *mPhysicsScene;

	//bool inited;
	//NxPhysicsSDK* mPhysicsSDK;
	UltimatePhysicsSubsystem *mPhysicsSubsystem;
	UltimateInputSubsystem *mInputSubsystem;

	Ogre::Light *light;
//	Terrain *test;
	ControlStatus controlStatus;
	Ogre::SceneManager* controlSceneManager;
	//std::map<Ogre::String, ControlLogic*, Ogre::String::compare<Ogre::String>> controlLogics;
	std::map<std::string, ControlLogic*> controlLogics;
	/*std::map<std::string, NxActorDesc*> actorDescMap;*/
	std::map<std::string, UltimatePhysicsActorDesc*> actorDescMap;

	std::vector<EntityControl*> controlEntityList;

	//Ogre::Entity * moveTest;

	ControlContext::GameStatus gameStatus;
	bool isAnyoneWaiting;
	bool mGameON;
	bool mGameOFF;
	Ogre::String mGameScript;
	Ogre::String mMenuScript;

	std::vector<Ogre::Vector3*>* calcCurve(luabind::object param);

	Ogre::RaySceneQuery *mRaySceneQuery;

	UltimateSoundSubsystem * gameAudio;

	MapConfiguration* mapConfig;

	int projectileCount;
	//HUD* mainHUD;


	Ogre::Root *mRoot;
	Ogre::Camera* mCamera;
	Ogre::SceneManager* mSceneMgr;
	//Ogre::OverlaySystem *mOverlaySystem;
	Ogre::Overlay* mDebugOverlay;
	Ogre::RenderWindow* mWindow;

	bool mShutDown;

	Ogre::Vector3 boxShapeDesc[3];

	ContactReport contactReport;

	CustomScriptFileReader * mScriptFileReader;
	bool customReaderUsed;

	GameOverHandler *mGameOverHandler;
	bool gameOverHandlerUsed;

	std::vector<std::string *> requiredGameResultList;

	int maxProjectileCount;

	//Network
	bool multiplayer;
	bool isServer;
	std::string targetIP;
	int targetPort;


public:
	Game(Ogre::Root *root,Ogre::RenderWindow* window);
	virtual ~Game(void);

	virtual void initGame();
	virtual void setScriptFileReader(CustomScriptFileReader * reader);
	virtual void  setGameOverHandler(GameOverHandler *gameOverHandler);

protected:
	virtual void createScene(void);
	virtual void createFrameListener(void);
	virtual void destroyScene(void);
	virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
	virtual bool configure();
	bool initMove();
	//binds the move to ControlStatus
	void initControlStatus();
	//Initializing PhysX
	void initPhysX();
	bool initNxScene();

	// You may remove the comment, if you want to test with PS Move only
	//virtual bool keyPressed( const OIS::KeyEvent &arg );
	// You may remove the comment, if you want to test with PS Move only
	//virtual bool keyReleased( const OIS::KeyEvent &arg );
	/*virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
	virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
	virtual bool mouseMoved( const OIS::MouseEvent &arg );*/
	virtual void processUnbufferedKeyInput(const Ogre::FrameEvent& evt);
	bool frameStarted(const Ogre::FrameEvent& evt);
	bool frameEnded(const Ogre::FrameEvent& evt);
	//void copyCameraImageToTexture(Ogre::TexturePtr texture);
	virtual void setupLuabindings();

	virtual void runScript(std::string luaFile);

	bool quit();
	void setupCollisions();


	void createMenu(Ogre::String script);
	void destroyMenu();
	void startGame(Ogre::String script);
	void createGame(Ogre::String script);
	void finishGame(Ogre::String script);
	void destroyGame();

	


	//functions for Luabind

	void SetAmbientLightColor(float r,float g, float b);
	void createSceneNode(luabind::object pos,luabind::object ori,luabind::object scale,luabind::object initializer);
	void addSceneNode(Ogre::SceneNode *node,Ogre::SceneNode *controlnode,luabind::object pos,luabind::object ori,luabind::object scale,luabind::object initializer);
	void addStaticEntity(Ogre::SceneNode *node,luabind::object param); 

	void createMap(Ogre::String skyBoxName, luabind::object mapConfiguration);
	void createMapPoints(int fromIndex, int toIndex);

	void addTrigger(EntityControl *ent,luabind::object initializer);
	void createDamageAction(Trigger *tr, luabind::object param);
	void createPositionReq(Trigger *tr, luabind::object param);
	void createGameOverAction(Trigger *tr);
	void createKillAction(Trigger *tr,std::string entityName);
	void createKilledReq(Trigger *tr);
	void createFreeRayReq(Trigger *tr, luabind::object param);
	void createExplodeAction(Trigger *tr);
	void createCustomScriptAction(Trigger *tr,luabind::object param);
	void createNegateReq(Trigger *tr, luabind::object initializer);
	void createFreeMoveAction(Trigger *tr,luabind::object param);
	void createOnRailMoveAction(Trigger *tr,luabind::object map);

	void addBodyRailControlLogic(std::string name, luabind::object param);
	void addPlayerProjectileControlLogic(std::string name, luabind::object initializer);
	void bindPojectileToKey(PlayerProjectileControlLogic * controLogic,std::string key,luabind::object param);
	void addTargetControlLogic(std::string name, luabind::object param, luabind::object initializer);
	void addTarget(TargetControlLogic* targetControlLogic,luabind::object param);
	void addProjectileTarget(TargetControlLogic* targetControlLogic,luabind::object param);
	void addPhysicsEntity(const Ogre::String &entityName, Ogre::SceneNode* node, Ogre::SceneNode* controlNode, luabind::object param,luabind::object initializer);
	void addEntity(const Ogre::String &entityName, Ogre::SceneNode* node, Ogre::SceneNode* controlNode, luabind::object param,luabind::object initializer);
	void addPhysicsBody(EntityControl *entity,Ogre::SceneNode* node,luabind::object param,luabind::object initializer);
	void addOgreBody(EntityControl *entity,Ogre::SceneNode* node,luabind::object param,luabind::object initializer);
	void addParticleSystemBody(EntityControl *entity,Ogre::SceneNode* node,luabind::object param,luabind::object initializer);
	void addNodeBody(EntityControl *entity,Ogre::SceneNode* node,luabind::object param,luabind::object initializer);
	void setMasterBody(EntityControl *entity,EntityBody * body);
	void addController(EntityControl *entity,Ogre::String controlLogicName);
	void setEntityStatus(EntityControl *entity, std::string status);

	void addGameResultEntry( std::string resultName,std::string entityName, std::string parameterName);

	void setGravity(float x, float y, float z);

	void addPhysicsTerrain(const Ogre::String &entityName, Ogre::SceneNode* node, Ogre::SceneNode* controlNode, luabind::object param);
	void setCamera(Ogre::SceneNode* node);
	void addLauncher(TargetControlLogic* targetControlLogic, luabind::object param);
	void addProjectile(Controller::Projectile projectile,
		Ogre::SceneNode* node, Ogre::SceneNode* controlNode, std::string controlLogicName);
	void setMaxProjectileCount(int max);
	void SetRoundCamera(luabind::object param);
	
	void createCamera(Ogre::SceneNode* node,luabind::object param);
	void createPSysAction(Trigger *tr, luabind::object param);
	void createSetVectorParameter(Trigger *tr, luabind::object param);

	void createActorDesc(luabind::object param,luabind::object initializer);
	void addBoxShapeDesc(std::string name,luabind::object param);

	void bindFunctionGUI(const Ogre::String button, luabind::object func);
	void loadLayoutGUI(const Ogre::String layout);
	void setWindowVisible( const Ogre::String window, bool modifier);
	void setCursorVisible(bool modifier);
	void bindButtonKey(std::string abstractKeyName, int keyId);
	void bindKey(std::string abstractKeyName, std::string keyId);

	//bool luaFuncCaller(const CEGUI::EventArgs &e);

	//----------------------------------------------------------------
	// Audio specific functions
	Ogre::Vector3 getAudioListenerPosition();
	Ogre::Vector3 getAudioListenerDirection();
	void setAudioListenerPose(Ogre::Vector3 pos, Ogre::Vector3 dir);
	void createAudioWithName(Ogre::String name, Ogre::String filePath, 
		bool looping, float pitch, luabind::object position);
	void setAudioWithName(Ogre::String name, Ogre::String filePath, 
		bool looping, float pitch, luabind::object position);
	void playAudioByName(Ogre::String name);
	void playAudioFromFile(Ogre::String filePath, bool looping,
		float pitch, luabind::object position);
	void stopAudioByName(Ogre::String name);
	void stopAllAudioSource();
	void deleteAllAudioSource();
	//----------------------------------------------------------------
	//AI

	EntityParameter* createVectorEntityParameter(std::string name,luabind::object pos);
	void createAIControlLogic(std::string name,luabind::object initializer);
	void addAIGoal(AIControlLogic * logic,luabind::object initializer);
	void addAIGoalRecord(AIGoal* goal,std::string targetParam, EntityParameter* parameter, luabind::object param);
	void addTriggerToGoal(AIGoal* goal, luabind::object initializer);

	//----------------------------------------------------------------
	//Network
	void createNetworkContrologic(std::string name, int id, bool serverEntity);
	void setTargetServer(std::string ip, int port);
	void createServer(int port);
	void startNetworkSession();
	void stopNetworkSession();


	//----------------------------------------------------------------
	void addHUD(EntityControl*);
private:
	void control(Ogre::Real);
	void nodeControl(const ControlContext&, Ogre::SceneNode*);
//	CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID);
	//Function for creating an entity
	
};

// Contact happened callback
//static bool myContactAddedCallback(
//	btManifoldPoint& cp,
//	const btCollisionObject* colObj0, int partId0, int index0, 
//	const btCollisionObject* colObj1, int partId1, int index1);


